home *** CD-ROM | disk | FTP | other *** search
/ Die Speccy' 97 / Die Speccy' 97.iso / amiga_system / the_aminet / dev / debug / apurify_v1_2.lha / doc / MIT-APurify.doc < prev    next >
Text File  |  1995-09-06  |  28KB  |  605 lines

  1.                   MIT-APurify v1.2.1
  2.                   ------------------
  3.  
  4.                MIT-syntax version (GCC).
  5.  
  6.                 (c) by Samuel DEVULDER
  7.                    Sept. 1995
  8.  
  9.                Samuel.Devulder@info.unicaen.fr
  10.  
  11. DESCRIPTION (SHORT):
  12. --------------------
  13.     This is APurify for compilers with MIT syntax asm-files. As  far  as  I
  14.     know only GCC uses such a syntax. So that version is indeed  a  version
  15.     for the GCC compiler. If you are using an  other  compiler,  then  read
  16.     MOT-APurify instead. In the following of that document, APurify  stands
  17.     for MIT-APurify, and I assume you're using the GCC compiler.
  18.  
  19.     APurify is a program that allows you to detect bad accesses  to  memory
  20.     of your programs without any kind of specific external  devices  (MMU).
  21.     It avoids bugs due to accessing memory not owned by your program.
  22.  
  23.     This is a port for APurify v1.1 on Aminet/dev/debug for GCC. I've  done
  24.     some little improvements so that it is not exactly the same as v1.1. It
  25.     may be full of bugs, so be carefull. I must add also that the port    was
  26.     harder than I thought to do (it's hard to port on  a  unkwown  compiler
  27.     with a strange syntax for assembler !).
  28.  
  29.  
  30. INSTALLATION:
  31. ------------
  32.     That archive contains the version of APurify for the  GCC  compiler
  33.     as well for other compilers. Here is a description of gcc-related files
  34.     of this archive for that version. It also gives you  what  to  do  with
  35.     those files to make an installation.
  36.  
  37.     - doc/MIT-APurify.doc    The file you are currently  reading. Put it
  38.                 with all your doc files. It is usefull from
  39.                 time to time.
  40.  
  41.     - doc/History        The whole history.  (this  file is not very
  42.                 usefull for common people). Do whatever you
  43.                 want with it.
  44.  
  45.     - bin/MIT-APurify    The parser tuned for the MIT syntax. Rename
  46.                 it as APurify and put it someware  in  your
  47.                 path.
  48.  
  49.     - lib/APur-gcc.a    The link-time library.    Rename it as APur.a
  50.                 and  put  it  someware    in   your   library
  51.                 search-path.
  52.  
  53.     - test/test.c        Source of a stupid test file.  Just here to
  54.                 let  you  remake  the  test   program.     Do
  55.                 whatever you want with it.
  56.  
  57.     - test/test.gcc     Test file  Apurify'ed.  Run it  to  see how
  58.                 APurify is useful :-).
  59.  
  60.  
  61. SYNOPSIS:
  62. --------
  63.     Usage: APurify [-revinfo] [flags] <inputfile> [-o <outputfile>]
  64.  
  65.     Where flags can be:
  66.        -br<Ax>    To set the base register
  67.        -tb    To test memory referenced through base register
  68.        -ts    To test memory referenced through stack register
  69.        -tl    To test memory referenced through local stack frame
  70.        -tp    To test pea instructions
  71.        -?,?,-h    To display this usage
  72.  
  73.     Flags can be anywhere on the command line and may be  merged  together.
  74.     But take care that flags that need an extra argument appear in the last
  75.     position. Thus "-tsoPROG.s" is good  and  will  output  a  file  called
  76.     "PROG.s" while "-otsPROG.s" is wrong and  will  output  a  file  called
  77.     "tsPROG.s" ! Here is a short description of arguments and flags:
  78.  
  79.     -revinfo    This displays informations  about APurify  (name,  size and
  80.         date of modules and number of  compilation  done  for  that
  81.         version).
  82.  
  83.     -br<Ax>    This  sets  the  base  register  used  to  reference memory
  84.         in SMALL_DATA model. Usually A4 is used  for  that  perpose
  85.         and that's the default. If A5  is  used  instead  then  add
  86.         -brA5 on your command line.
  87.  
  88.     -tb     This enable APurify to check all referenced  memory through
  89.         the base register (see -br). If you are using a  SMALL_DATA
  90.         model, add this flag on  your  command    line.  By  default,
  91.         APurify won't check  memory  referenced  through  the  base
  92.         register.
  93.  
  94.         NOTE: for safest check, you should always use that  option,
  95.         even if you're not in smalldata model (A4 may  be  used  as
  96.         a temporary register in that case).
  97.  
  98.     -ts     This  enable  APurify to  check memory referenced  by stack
  99.         pointer (SP or A7). By default  APurify  won't  check  such
  100.         memory accesses (to reduce the code size and  increase  the
  101.         runtime speed). That option will detect when  you  have  no
  102.         more room on your stack (stack overflow).
  103.  
  104.     -tl     This enable APurify to check  memory  referenced   by local
  105.         stack pointer (the one that is link'ed and  unlink'ed  when
  106.         enterring and exiting a C-function). By  default,  this  is
  107.         switch off. This  option  allow  APurify  to  detect  stack
  108.         overflow.
  109.  
  110.     -tp     This enable APurify to check indirect  adresses pushed onto
  111.         the stack by using a pea. By  default  this  is  off.  When
  112.         used, that option will check things like "pea  a2@(10)"  or
  113.         the like. This can help  you  with  memory  accessed  by  a
  114.         pointer in a code that has not been APurify'ed. For example
  115.         this is usefull  for  things  like  fread(&ptr[10],10,1,fp)
  116.         because in that case the "pea a2@(10)" used to push on  the
  117.         stack &ptr[10] will be checked and if ptr[10] is not  owned
  118.         by your program, you'll get an APurify error.  Please  note
  119.         that this may no work all the time  since  &ptr[0]  can  be
  120.         translated as "movel a0,sp@-" which  won't be checked.
  121.  
  122.     -o <outputfile>
  123.         This specifies the name of the outputfile. If  ommited    the
  124.         outputfile will be the same as the inputfile (source file).
  125.  
  126.     -?
  127.     -h
  128.     ?        Obvious options.
  129.  
  130.  
  131. DESCRIPTION (A BIT LONGER):
  132. --------------------------
  133.     As a general rule, at the microprocessor level, there is  two  kind
  134.     of ways to access memory. There is direct access and indirect access to
  135.     memory. For example, in C, direct access can be viewed as accessing  to
  136.     global variables. Indirect access corresponds  to  accessing  an  array
  137.     value. More precisely, direct access corresponds to reading or  writing
  138.     a variable whose address is known at compilation  time  (or  since  the
  139.     loading of the program into the memory). Indirect access  is  used    for
  140.     variables whose adress is dynamicaly determined  by  the  program.    For
  141.     example, if p is a pointer to an array allocated by malloc(), *p is  an
  142.     indirect access. Such an access occur also in case of instruction  like
  143.     T[i] where T is a global array, because the  address  of  T[i]  is    not
  144.     known at compilation time, since it depends on the index value i. Using
  145.     indirect access to memory is called indirection.
  146.  
  147.     A regular program must not access memory not owned by it. That kind
  148.     of access can be qualified as illegal.
  149.  
  150.     Illegal direct access  to   memory  is    not  possible, because     by
  151.     definition, only global  variables can be  accessed that  way and those
  152.     variables belongs obviously to the program    (except for code written in
  153.     assembly   language   that    references  absolute   values, for example:
  154.     "btst  #6,$bfe001"; but that  kind of  code  is not a  good programming
  155.     :-)). So we can assume that direct access to memory is always right.
  156.  
  157.     On the other hand,  it is sure    that indirect access to  memory can
  158.     be illegal.  Many bugs are made by    overstepping array  boundaries.  If
  159.     that oversteppings are  in reading a value, there  is not much  trouble
  160.     for over running tasks (it is an error inside your  task); but if it is
  161.     in writing you may directly interfere with other tasks and big mess can
  162.     happen (total breakdown of the system).
  163.  
  164.     APurify works on  that kind of access  by verifying the validity of
  165.     indirect access to memory. It remebers the memory that was allocated by
  166.     the program and check the integrity of  each access. One can think that
  167.     makes a lot of tests ! Well, yes, but APurify is  not  designed  to  be
  168.     used in the general use of programs; just  in  test  phases.  Moreover,
  169.     indirections  do  no  occur  very  often  actually.  Only    array-based
  170.     variables produces indirections.  Thus,  the  variables  on  the  stack
  171.     --although being accessed by  indirection--  are  not  checked  because
  172.     their access is always safe (at least if there is no stack overflow !).
  173.     Also, in SMALL_DATA model, global  variables  access  is  done  through
  174.     indirection, but they are not checked.
  175.  
  176.     If an illegal access is found, APurify displays an error message on
  177.     the error stream of the program (have a look at the full  justification
  178.     of the output when using verbose mode :^). There is two kind of illegal
  179.     accesses. Some are accesses  to  memory  that  doesn't  belong  to  the
  180.     program (it is called  an  access  between  blocks),  some  others  are
  181.     accesses to a part of memory owned by a program and an other  part    not
  182.     owned by it (it is an overstepping  of  a  block).  You  can  see  this
  183.     visually: If [ 1 ] and [ 2 ] represent  two  blocks  allocated  by    the
  184.     program and ( 3 ) the memory accessed, then
  185.  
  186.          ---- [ 1 ] ---- ( 3 ) ---- [ 2 ] ---->
  187.         0                       increasing address
  188.  
  189.     corresponds to the first kind of illegal access and
  190.  
  191.              ---- [ 1 ( ] 3 ) ---- [ 2 ] ----->
  192.     or
  193.              ---- [ 1 ] ---- ( 3 [ ) 2 ] ----->
  194.  
  195.     corresonds to the second kind of access. The first kind is very  common
  196.     but the second is quite rare (it's rather a misaligment problem).
  197.  
  198.     APurify has two output modes. One is verbose an tries to  give    lot
  199.     of informations by using words. The other one is more brief  and  gives
  200.     you the same informations but you'll have to decode them.
  201.  
  202.     When APurify starts and ends, it outputs  the  date/time.  This  is
  203.     useful if you are using logfiles. With that, you can keep all your logs
  204.     in a  single  file    and  retrieve  any  execution  with  it's  date  of
  205.     execution.
  206.  
  207.     In case of an error, APurify displays some  text.  The    first  line
  208.     looks like this one:
  209.  
  210.     **** APURIFY ERROR ! [$<N1>(<N2>) <ATTR> (<TEXT1>)] <TEXT2>:
  211.  
  212.     That line represent  the  accessed    memory.  <N1>  is  the    hexadecimal
  213.     address accessed. <N2> is the length of the access (in decimal). <ATTR>
  214.     represents the type of acess. <TEXT1> allows you to find where in  your
  215.     code the illegal accessed had happened. <TEXT2> describe  the  kind  of
  216.     illegal access.
  217.  
  218.     If the length (<N1>) is 1, then it was a byte access. 2 stands  for
  219.     a short access,  4    for  a    int/long  and  >4  for    movem  instruction.
  220.     Attributes, <ATTR>, can be "R--" or "-W-". The first one represents  an
  221.     access in reading a value and the second an access in writing a value.
  222.  
  223.     The text <TEXT1> look like this:
  224.  
  225.         <NAME>, PC=$<PC#> HUNK=$<HUNK#> OFFSET=$<OFF#>
  226.  
  227.     <NAME> is the name of the subroutine where the  error  occured.  It  is
  228.     always displayed (even if it is a "static" one). The rest of  the  line
  229.     can be partially displayed, showing as much informations as APurify can
  230.     get. <PC#> is a hexadecimal address pointing to  the  instruction  that
  231.     produced the error. <HUNK#> and <OFF#> are    the  hunk  number  and    the
  232.     relative offset of <PC#>. Using <HUNK#> and <OFF#> and a  disassembler,
  233.     you can very easilly find where your code is bad (BTW, I use dobj  from
  234.     netdcc, (c) by Matt Dillon). Please note  that  <PC#>  can  point  some
  235.     instruction before the faultly one. In that case, it will  point  to  a
  236.     PEA followed by a JSR. As those instructions does not  belong  to  your
  237.     code (they are APurify stuff), the involved instruction  is  the  third
  238.     one. That will happen only if  an  instruction  references    memory    two
  239.     times and if the first access is wrong. It is a little bit annoying but
  240.     it is better than nothing and it is quite rare :-).
  241.  
  242.     The remaining lines show the context  of  the  illegal    access.  It
  243.     gives you informations about the  surronding  memory  blocks  owned  by
  244.     your program. Each    block  is  displayed  according  to  the  following
  245.     pattern:
  246.  
  247.                [$<N1>(<N2>) <ATTR> (<TEXT>)]
  248.  
  249.     where <N1> is the hexadecimal address of the beginning  of    the  block,
  250.     <N2> its length (in decimal). Note that  the  length  may  seem  to  be
  251.     longer than the one allocated by malloc() and  the  address  may  point
  252.     before the one you obtained via malloc(). This is not wrong !  In  fact
  253.     you must know that the malloc() subroutine may  add  some  informations
  254.     (like an double-chained list or the length of the  allocation)  to  the
  255.     block you've requested. Those extra informations  are  put  before  the
  256.     address you recieve. That explain this behavior.  In  this    version  of
  257.     APur.lib, this takes 12 ($C) extra bytes. So if you allocate 10  bytes,
  258.     don't be suprised if APurify thinks you've requested 22 bytes.
  259.  
  260.     <ATTR> are 3 status characters RWS
  261.  
  262.     where R means: read-enable block
  263.           W means: write-enable block
  264.           S means: system block (block not controlled by the program).
  265.  
  266.     If one access is forbidden, the letter '-' replaces  the  corresponding
  267.     character. <TEXT> is actually  the    name  of  the  procedure  that    has
  268.     allocated the block. If it ends with "*" that block was allocated by  a
  269.     call to a subroutine not parsed by APurify during the execution of    the
  270.     one indicated (a library call, maybe).
  271.  
  272.     With each block you can find an offset. That offset is the distance
  273.     between that block and the faultly address. In verbose  mode,  you    can
  274.     see some text explaining things about the relative position of a  block
  275.     and the accessed memory. In non-verbose  mode  you    can  just  see    the
  276.     offsets followed by the blocks. The shorter offset is  displayed  first
  277.     since that block is the one that is more likely overstepped.
  278.  
  279.     When an illegal writing occur (the only dangerous thing you can  do
  280.     by indirection, indeed), APurify tells you    to  that  error  is  really
  281.     dangerous and asks if you wish to stop your program. If  you  wish    so,
  282.     exit() is called. You can also ignore that error  or  ignore  all  such
  283.     errors (but then you'll surely meet the guru !).
  284.  
  285.     APurify checks the memory allocated but not freed by  the  program.
  286.     (in fact, it detects non deallocated-blocks on library-closing time).
  287.  
  288.     It  knows  about  memory  location  independant  of   the   program
  289.     execution. That is to say, the first kilobyte of memory  that  contains
  290.     interrupt vectors of the 680x0 processor, the program segments and    the
  291.     stack. Accessing to those blocks will not be illegal. They    got  the  S
  292.     attribute (for SYSTEM blocks).
  293.  
  294.     It takes into  account    memory    block  allocated  by  malloc()  and
  295.     AllocMem(), and indirect allocated block (by OpenScreen() for example).
  296.     But I did not test the last kind of allocation. Anyway,  it  should  be
  297.     ok, because APurify patches AllocMem()  &  FreeMem()  entries.  Thus  a
  298.     program can access to the bitplanes of one of its screen without error.
  299.  
  300.     If  the  program  makes  a  legal  access,   but   attributes    are
  301.     incompatible  with    the  access-kind,  a  protection-error    message  is
  302.     displayed. Actually only the first    kilobyte  is  read/write-protected.
  303.     But it may change in the future.
  304.  
  305.     In order to speed up block  searching,    APurify  uses  a  cache  of
  306.     recently accessed blocks. Thus, even if there  is  a  large  amount  of
  307.     memory blocks, execution should not be slowed down too much. (but I must
  308.     say I doubt it is efficient enough).
  309.  
  310.  
  311. HOW TO USE APURIFY:
  312. ------------------
  313.     One can see APurify as a pre-assembler. It must be used on assembly
  314.     language sourcefile just before the assembler takes place. It scan    the
  315.     file and change it a bit so that APur.a can be used.
  316.  
  317.     Normal way to use it for a C program is to:
  318.  
  319.     - compile C sourcefiles and leave assembly language source (.s).
  320.     - use APurify on each .s file.
  321.     - compile your .s file to get a .o file
  322.     - link all .o files together with APur.a.
  323.  
  324.     For example, using gcc on prog.c it gives
  325.  
  326.     CLI> gcc -g prog.c -o prog.s -S
  327.     CLI> APurify -tb prog.s
  328.     CLI> gcc -g prog.s -o prog -lAPur
  329.  
  330.     As you can see, APurify needs no change to your C  files  to  be  used.
  331.     However, the library must be opened by calling AP_Init() in the  main()
  332.     function. Note that now, you need not call AP_Close() anymore (even  if
  333.     you can still call it but for nothing (it is  automatically  called  on
  334.     exit()). But do not use Exit() to abort your  program,  I  think  it'll
  335.     crash if  APurify  is  running.  If  you  must  use  Exit()  then  call
  336.     AP_Close() just before calling Exit(). The explantion is simple:  since
  337.     some system functions are patched, if a program exits  without  closing
  338.     the library, those patch will be corruped, pointing to a code  that  is
  339.     nomore in memory and you'll  meet  the  guru  (ie:  the  computer  will
  340.     crash)... (You've been warned :-).
  341.  
  342.     If you forget to open the library, a warning message will tell    you
  343.     about that and the program will go just as if it  wasn't  processed  by
  344.     APurify.
  345.  
  346.     You can disable/enable printing of messages by    making    a  call  to
  347.     AP_Report(flag). If  flag  is  true  (ie.  different  from  zero)  then
  348.     printing is enabled, if it is false (ie. equal to zero), no output will
  349.     be done. This is usefull for startup-codes. For  example,  if  you    are
  350.     using the argv[] array in C, APurify will make  a  lot  of    false-error
  351.     printing. This is because the values pointed by this array is allocated
  352.     before  the  library  is  opened.  You  can  avoid    this   by   calling
  353.     AP_Report(0) before, and AP_Report(1) after, the code that uses argv[].
  354.  
  355.     When debugging an APurify'ed program, you can put a  breakpoint  on
  356.     a function called AP_Err(). That function AP_Err() is called each  time
  357.     APurify detects an error. With that, you'll have the occasion  to  look
  358.     at your program just before a faultly memory-access occur.
  359.  
  360.     You can switch    from  a  verbose  output  to  a  shorter  one  with
  361.     AP_Verbose(flag). IF flag is true then the verbose mode is on. If it is
  362.     false then only short messages will be printed. Some people prefer    the
  363.     later so that is the default. If you perfer the verbose ouput then    put
  364.     AP_Verbose(1)  someware  in  your  code  and  you'll  get  some  longer
  365.     explanations about illegal accesses.
  366.  
  367.     You can specify a logfile where APurify can put its errors.  To  do
  368.     this, set the environment variable "APlog" (file env:APlog) to  a  name
  369.     of a logfile. If this variable is set, then APurify will append all its
  370.     outputs to the file indicated.
  371.  
  372.     You can use APurify on any  language  that  generates  a  temporary
  373.     assembly language sourcefile (included assembly itself :-) ). You  must
  374.     notice too, that you can use it on programs for which no source-code is
  375.     available (or .o files without .asm files). For  that,  use  a  program
  376.     that  can  do  reverse  engineering  on  your  executable    (ie:   that
  377.     disassembles the executable and  produces  a  .asm    file  ready  to  be
  378.     assembled). Then, with minor changes (prepend '_'  and  append  ':'  to
  379.     every interesting labels, put a call to AP_Init in    the  right  place),
  380.     you get a file ready to be processed by APurify. If the processed  file
  381.     has a HYNK_SYMBOL then you are very lucky and  you    need  not  work  on
  382.     labels. You then just have to find the "_main:" and add "jbsr _AP_Init"
  383.     as the first instruction of the "_main:" subroutine.
  384.  
  385.     Note:  you  can  use  ADIS  (by Martin Apel)  on  aminet  to do reverse 
  386.     engineering (it seems to be quite good a tool to do it).
  387.  
  388.  
  389. EXAMPLE:
  390. -------
  391.     As an example, let's look at the test program. You'll see  how  you
  392.     can use the APurify report it produces to  find  what's  wrong  in  the
  393.     program. For this, I've included in that document the commented report.
  394.     My comments/explanations appear on lines beginning with a "#".
  395.  
  396.     **** APurify started on Tue Aug 22 22:27:18 1995
  397.  
  398.     #
  399.     # Well, the report started...
  400.     #
  401.  
  402.     **** APURIFY ERROR ! [$002908bc(4)  R--  (_main,  PC=$00279446  HUNK=$0
  403.     OFFSET=$23e)] accessed between:
  404.         -25     [$002908d8(27) RW- (_main*)]
  405.         +41     [$00286c48(40012) RW- (_main*)]
  406.  
  407.     # Hum... First hit... it is an error in reading something in the main()
  408.     # procedure between two blocks already  allocated.    The  nearest  block
  409.     # appears in first position, so we can think that the error was done by
  410.     # accessing an array allocated in main() with a negative index. We  can
  411.     # look at the code to find what is wrong with it. Using DOBJ, we  found
  412.     # at offset $23e in the first hunk the following code:
  413.     #
  414.     #        00.0000023e  4852               PEA.L   (A2)
  415.     #        00.00000240  4eb9 AP_WriteL        JSR       AP_WriteL
  416.     #        00.00000246  24ab ffd8           MOVE.L -40(A3),(A2)
  417.     #
  418.     # The  pointed  instruction  is  a    PEA  followed  by  a  JSR.  So    the
  419.     # interesting instruction is the third one. This corresponds to  the  C
  420.     # code:
  421.     #
  422.     #                   a[0]=b[-10]
  423.     #
  424.     # Hence we've discovered a first error in the code. Note  that  -25  is
  425.     # the distance (in bytes) between the end of the  accessed  memory  and
  426.     # the beginning of the array. This is not the  difference  between    the
  427.     # beginning address of the two blocks!
  428.     #
  429.  
  430.     **** APURIFY ERROR ! [$00283af8(4)  R--  (_main,  PC=$00279478  HUNK=$0
  431.     OFFSET=$270)] accessed between:
  432.         +1        [$00283ae8(16) RW- (_main*)]
  433.         -61     [$00283b38(412) RW- (_main*)]
  434.  
  435.     #
  436.     # Well... here it seems to be an access just after an allocated  block.
  437.     # the offset +1 is the distance in bytes between the accessed block and
  438.     # a allocated block. The situation is like this:
  439.     #
  440.     #              ---------[ 1 ]( 2 )---------->
  441.     #
  442.     # Where "[ 1 ]" is the allocated block and "( 2 )" the accessed  block.
  443.     # If we look in the code, we find:
  444.     #
  445.     #        00.00000270  4aaa 0004           TST.L   4(A2)
  446.     #
  447.     # that correponds to the test done by "if(a[1] == 0)". This is an error
  448.     # since the array 'a' is just 16-12=4 bytes long. So a[1] points out of
  449.     # the array!
  450.     #
  451.  
  452.     **** APURIFY ERROR !  [$00283af6(4)  R--  (_read_shifted,  PC=$00279302
  453.     HUNK=$0 OFFSET=$fa)] accessed across the ending boundary of:
  454.         -2        [$00283ae8(16) RW- (_main*)]
  455.  
  456.     #
  457.     # Hehe another error... Damn ! That test program is a  FULL  of  bug  !
  458.     # Yes, but that one is an other kind of error. It is an access across a
  459.     # boundary. That occur in the read_shifted() code. We need not look  in
  460.     # the asm file to see the  error.  Here  it  is  a    misaligment  error.
  461.     # Visually that gives:
  462.     #
  463.     #               ------------[ 1(]2 )----------->
  464.     #
  465.     #           [ 1 ] = allocated       ( 2 ) = accessed.
  466.     #
  467.  
  468.     ****  APURIFY  ERROR  !  [$00283af4(4)  R--  (_read_long,  PC=$00279332
  469.     HUNK=$0 OFFSET=$12a)] accessed between:
  470.         -65     [$00283b38(412) RW- (_main*)]
  471.         +11901  [$0027ec78(8192) RWS (standard stack frame of task)]
  472.  
  473.     #
  474.     # That error is strange! It is  not  an  access  to  an  array  with  a
  475.     # negative index as one think immediately: We never call read_long() in
  476.     # such a way. Indeed, the accessed memory  was  right  some  times    ago
  477.     # since it lays in the array 'a' (look at the second  hit).  Hence,  it
  478.     # must be an access to a freed memory. That  error    is  then  obviously
  479.     # found in the code:
  480.     #
  481.     #              free_arg(a); read_long(a).
  482.     #                   ^^^^^^^^^^^^
  483.     # NOTE: You can see that the program ran with a stack of 8192 bytes.
  484.     #
  485.  
  486.     **** APURIFY ERROR ! [$00000004(4) R--  (_read_page_zero,  PC=$00279396
  487.     HUNK=$0 OFFSET=$18e)] accessed on a read-protected block:
  488.         +4        [$00000000(1024) --S (Basic 680x0 vectors)]
  489.  
  490.     #
  491.     # Here the error is obvious, were are reading the zero-page. If it    was
  492.     # in writing, that error would be very dangerous.
  493.     #
  494.  
  495.     ****  APURIFY  WARNING  !  Closing    library  without  deallocation     of
  496.     the following block(s):
  497.         - [$00283b38(412) RW- (_main*)]
  498.         - [$00283d18(12012) RW- (_main*)]
  499.         - [$00286c48(40012) RW- (_main*)]
  500.  
  501.     #
  502.     # The program has exit()ed. APurify tells us that we've forget to  free
  503.     # those blocks. It    is  a  case  of  memory  leak.    Those  blocks  were
  504.     # allocated in main(). They appear in order of allocation.  Those  were
  505.     # allocated and lost by
  506.     #
  507.     #           a=malloc(4),malloc(400),malloc(12000),malloc(400000)
  508.     #
  509.     # since the ",,," returns the leftmost value.
  510.     #
  511.  
  512.     **** APurify ended on Tue Aug 22 22:27:18 1995
  513.  
  514.     #
  515.     # Well... done :-).
  516.     #
  517.  
  518.     NOTE: I hope this example is clear enough.. but I'm not sure.. tell  me
  519.     :^).
  520.  
  521.  
  522. LEGAL PART:
  523. ----------
  524.     That program is provided 'AS IS'. I  am  not  responsible  for  any
  525.     dammage it can cause (but I am responsible for the benefits it can give
  526.     to you :-). Use that software at you own risks.
  527.  
  528.     That program is FREEWARE. You can use and distribute it as long  as
  529.     you keep the archive  intact  (no  adulteration  of  files  except  for
  530.     compression). It can't be sold without my agreement (except  a  minimal
  531.     amount for media support). You must ask me for commercial use  of  (any
  532.     part of) that product. I keep all my rights on  that  program  and    its
  533.     future releases. I can modify that software without telling it  to    the
  534.     users.
  535.  
  536.     If you wish, you can send me a postcard or anything else  you  want
  537.     (money, documentation, amiga, hardware  stuff,  ...)  in  exchange  for
  538.     using APurify. But there is no obligation :-). My postal address is:
  539.  
  540.         M. DEVULDER Samuel
  541.         1, Rue du chateau
  542.         59380 STEENE
  543.         FRANCE
  544.  
  545.     (yes I'm french !). You can  send  suggestions  or  bugs  to  my  email
  546.     address:
  547.  
  548.         devulder@info.unicaen.fr
  549.  
  550.  
  551. NOTES:
  552. -----
  553.     My configuration is: one old A500 (1989), 2Mo RAM, 1  diskdrive,  1
  554.     HARD_DRIVE [300Mo, 10% full :-)], KS1.3 and a lot of  patience  (ah,  I
  555.     wish I had an A4000/040/33Mhz that does  not  meet    the  guru  all    the
  556.     time !).
  557.  
  558.     It has been compiled with cross-gcc 2.7.0  with  libnix  on  a    Sun
  559.     sparc.
  560.  
  561.     I had the idea of that program    after  a  chat    with  Cedric  BEUST
  562.     (AMIGA NEWS) on IRC (Internet Relay Chat). Thanks Cedric !
  563.  
  564.     I wish to thank Philippe Brand for his help  in  my  port.  He    was
  565.     really patient, even when I was really annoying (:-)). Thank you PHB !
  566.  
  567.     All marks are proprietary of their respective owners.
  568.  
  569.     There are some programs like APurify. For example,  FORTIFY  (Simon
  570.     P. Bullen), but  it  only  detects    illegal  writes  to  boundaries  of
  571.     allocated blocks. Thus it can't detect big oversteps and  oversteps  in
  572.     reading and the detection is not real-time. Enforcer can detect illegal
  573.     access to memory (I think), but it needs a special device (MMU).
  574.  
  575.  
  576. HINTS & TIPS:
  577. ------------
  578.     You can see some memory leaks with that version of APurify.  It  is
  579.     not really good but it can help. Memory leak  occur  when  a  block  of
  580.     memory is nomore pointed by your  program.    Those  memory  blocks  will
  581.     necessary be displayed when your  program  exit()s.  So  with  all  the
  582.     messages printed on that occasion, you can find such  blocks.  I  known
  583.     this is not so great, but I think it can help you a little    bit  (maybe
  584.     in a future version I'll build some code to really check memory leaks).
  585.  
  586.  
  587. BUGS:
  588. ----
  589.     APurify don't known public memory where a program can read or write
  590.     without having allocated it. Thus, it  will  report  an  error  when  a
  591.     program reads or writes values in a message obtained  through  GetMsg()
  592.     calls. Use AP_Report() to avoid such reports.
  593.  
  594.     It can display messages about closing the library  without  freeing
  595.     some memory blocks. This is due to printf() that allocates memory  that
  596.     is free'd on exit. This is not a real bug, but you can  avoid  this  by
  597.     doing a AP_Report(0) just before exiting. But you must notice  that  it
  598.     is better to display false bugs than to not display real ones.
  599.  
  600.     I've rewritten malloc()/realloc()/free().  I  hope  this  will  not
  601.     produce bugs (I've tested sucessfully the test program with  libnix and
  602.     ixemul, so I hope it will be all right).
  603.  
  604.     Certainly more bugs, but I'm waiting for your bug-reports.
  605.